﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProgNetDxComponents.ExtenderProviders.Options
{
    public abstract class OptionGrabber
    {
        /// <summary>
        /// Fires when option(s) is saved, Parameter is option name, or null if all options ware saved
        /// </summary>
        public static event EventHandler<OptionChangedEventArgs> OptionChanged
        {
            add
            {
                if (value != null &&
                    value.Target != null)
                {
                    List<EventHandler<OptionChangedEventArgs>> l = null;
                    if (eventsForComponents.ContainsKey(value.Target))
                    {
                        l = eventsForComponents[value.Target];
                    }
                    else
                    {
                        l = new List<EventHandler<OptionChangedEventArgs>>();
                        eventsForComponents.Add(value.Target, l);
                    }
                    l.Add(value);
                    if (value.Target is System.Windows.Forms.Form)
                    {
                        (value.Target as System.Windows.Forms.Form).FormClosed += new System.Windows.Forms.FormClosedEventHandler(OptionGrabber_FormClosed);
                    }
                    else if (value.Target is System.ComponentModel.Component)
                    {
                        (value.Target as System.ComponentModel.Component).Disposed += new EventHandler(OptionGrabber_Disposed);
                    }
                }
                else if (value != null)
                    events.Add(value);
            }
            remove
            {
                if (value != null &&
                    value.Target != null)
                {
                    if (eventsForComponents.ContainsKey(value.Target))
                    {
                        eventsForComponents[value.Target].Remove(value);
                    }
                }
                events.Remove(value);
            }
        }

        static void OptionGrabber_Disposed(object sender, EventArgs e)
        {
            if (eventsForComponents.ContainsKey(sender))
            {
                eventsForComponents[sender].Clear();
                eventsForComponents.Remove(sender);
            }
        }

        static void OptionGrabber_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            if (eventsForComponents.ContainsKey(sender))
            {
                eventsForComponents[sender].Clear();
                eventsForComponents.Remove(sender);
            }
        }

        private static List<EventHandler<OptionChangedEventArgs>> events = new List<EventHandler<OptionChangedEventArgs>>();
        private static Dictionary<object, List<EventHandler<OptionChangedEventArgs>>> eventsForComponents = new Dictionary<object, List<EventHandler<OptionChangedEventArgs>>>();

        private static void OnOptionChanged(params string[] opt)
        {
            OptionChangedEventArgs e = new OptionChangedEventArgs(opt);
            if (events.Count > 0)
            {
                foreach (EventHandler<OptionChangedEventArgs> ev in events)
                    ev(null, e);
            }
            foreach (List<EventHandler<OptionChangedEventArgs>> l in eventsForComponents.Values)
            {
                foreach (EventHandler<OptionChangedEventArgs> evl in l)
                    evl(null, e);
            }
        }

        protected abstract bool _SetOptionValueDirect(string name, object value);
        protected abstract bool _SetOptionValue(string name, object value);
        List<string> ChangedOptions = new List<string>();

        public void SetOptionValue(string name, object value)
        {
            if (_SetOptionValue(name, value))
                ChangedOptions.AddIfNotExist(name);
        }

        public abstract bool HasOption(string name);
        protected abstract void _GetAllOptions();

        public void GetAllOptions()
        {
            _GetAllOptions();
            ChangedOptions.Clear();
            OnOptionChanged(null);
        }

        public bool SetOptionValueDirect(string name, object value)
        {
            bool res = _SetOptionValueDirect(name, value);
            OnOptionChanged(name);
            return res;
        }

        public abstract object GetOptionValue(string name);

        protected abstract bool SaveOptions();

        public bool SaveAllOptions()
        {
            string[] op = ChangedOptions.ToArray();
            bool result = SaveOptions();
            if (result)
            {
                ChangedOptions.Clear();
                OnOptionChanged(op);
            }
            return result;
        }
    }
    public class OptionChangedEventArgs : EventArgs
    {
        string[] _OptionNames;
        public OptionChangedEventArgs(params string[] options)
        {
            _OptionNames = options;
        }
        public string[] OptionNames
        {
            get { return _OptionNames; }
        }

    }
}
